#pragma once

#include "Structs.h"
#include <boost/variant/static_visitor.hpp>

namespace GenParser
{
	struct SemanticModelBuilder : boost::static_visitor<>
	{
		SemanticModelBuilder(SemanticModel::ModelPtr model);
		
		void operator()(OperationsDef const& operations) const;
		void operator()(AbstractOperationsDef const& operations) const;
		void operator()(GeneralizationDef const& inheritance) const;
		void operator()(ImplementationDef const& implementation) const;
		void operator()(EmptyItem const& inheritance) const;
		void operator()(ContainsDef const& contains) const;
		void operator()(CompositionDef const& composition) const;
		
	private:
		void addOperations(const std::wstring& essenseName,
			const std::vector<SingleOperationDef>& operations, bool isAbstract) const;
			
		void connectEssenses(const std::vector<std::wstring>& essenseNamesA,
			SemanticModel::RelationType relationType,
			const std::vector<std::wstring>& essensesNamesB) const;
			
		inline void connectEssenses(std::wstring essenseNameA,
			SemanticModel::RelationType relationType,
			const std::vector<std::wstring>& essensesNamesB) const;
						
		inline void connectEssenses(const std::vector<std::wstring>& essenseNamesA,
			SemanticModel::RelationType relationType,
			std::wstring essenseNameB) const;

		inline void connectEssenses(std::wstring essenseNameA,
			SemanticModel::RelationType relationType,
			std::wstring essenseNameB) const;

		SemanticModel::ModelPtr _model;
	};

	void SemanticModelBuilder::connectEssenses(std::wstring essenseNameA,
		SemanticModel::RelationType relationType,
		const std::vector<std::wstring>& essensesNamesB) const
	{
		StringVector essenseNamesA;
		essenseNamesA.push_back(essenseNameA);
		connectEssenses(essenseNamesA, relationType, essensesNamesB);
	}
			
	void SemanticModelBuilder::connectEssenses(const std::vector<std::wstring>& essenseNamesA,
		SemanticModel::RelationType relationType,
		std::wstring essenseNameB) const
	{
		StringVector essensesNamesB;
		essensesNamesB.push_back(essenseNameB);
		connectEssenses(essenseNamesA, relationType, essensesNamesB);
	}

	void SemanticModelBuilder::connectEssenses(std::wstring essenseNameA,
		SemanticModel::RelationType relationType,
		std::wstring essenseNameB) const
	{
		StringVector essenseNamesA;
		essenseNamesA.push_back(essenseNameA);
		connectEssenses(essenseNamesA, relationType, essenseNameB);
	}

}